Skip to content

Introduce wp db users command for user management#303

Open
Copilot wants to merge 14 commits intomainfrom
copilot/add-wp-db-users-command
Open

Introduce wp db users command for user management#303
Copilot wants to merge 14 commits intomainfrom
copilot/add-wp-db-users-command

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 19, 2026

Implementation Plan

  • Analyze repository structure and existing commands
  • Create DB_Users_Command class with create subcommand
  • Add MySQL user creation with privileges
  • Update db-command.php to register the new command
  • Update composer.json with new command
  • Create Behat feature tests
  • Fix code style and static analysis issues
  • Refactor to extend DB_Command for better code reuse
  • Improve SQL escaping to prevent injection vulnerabilities
  • Simplify code by removing unnecessary wrapper methods
  • Pass all linting, code style, and static analysis checks
  • Perform code review and security checks
  • Make esc_sql_ident protected in parent class and use static calls
  • Remove assert calls per review feedback
  • Enhance SQL string escaping to handle all MySQL special characters
  • Remove redundant @var annotations and use explicit type casting

Summary

Implemented wp db users create command that allows database administrators to easily create MySQL user accounts with optional privileges on the WordPress database. The implementation extends DB_Command for consistency, follows WP-CLI patterns, and includes comprehensive tests. Latest changes remove redundant @var annotations as requested, using explicit type casting with PHPStan ignore comments where needed for the conditional return type from the parent method.

Original prompt

This section details on the original issue you should resolve

<issue_title>Introduce wp db users</issue_title>
<issue_description>One of the most common tasks database administrators need to do is create user accounts for applications with full privileges to the application's database. I propose that we make that super simple in wp-cli using syntax similar to:

wp db users create --user --host --pass --privilegeduser --privilegedpass

Name of the database user to create.
Hosts that are permitted to connect as .
New user's password.
Database user with sufficient privileges to execute the command.
Privileged user's password.

This create command could be augmented by including list, delete, etc.</issue_description>

Comments on the Issue (you are @copilot in this section)

@danielbachhuber I'm open to considering something like this, if someone would like to open a pull request for it.

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 19, 2026

Codecov Report

❌ Patch coverage is 93.33333% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
db-command.php 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@swissspidy

This comment was marked as resolved.

Copilot AI and others added 3 commits January 19, 2026 13:15
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
…utput.txt

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

Copilot AI changed the title [WIP] Introduce wp db users command for user management Introduce wp db users command for user management Jan 19, 2026
Comment thread src/DB_Users_Command.php Outdated
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
@swissspidy

This comment was marked as resolved.

gemini-code-assist[bot]

This comment was marked as resolved.

Comment thread src/DB_Users_Command.php Outdated
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Copilot AI requested a review from swissspidy March 11, 2026 17:16
@swissspidy swissspidy marked this pull request as ready for review March 11, 2026 21:40
@swissspidy swissspidy requested a review from a team as a code owner March 11, 2026 21:40
@swissspidy swissspidy modified the milestones: 2.1.5, 2.1.6 Mar 17, 2026
Comment thread phpcs.xml.dist Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/DB_Users_Command.php
Comment on lines +70 to +75
// Escape identifiers for SQL
// @phpstan-ignore cast.string (PHPStan doesn't infer conditional return type from parent method)
$username_escaped = (string) self::esc_sql_ident( $username );
// @phpstan-ignore cast.string (PHPStan doesn't infer conditional return type from parent method)
$host_escaped = (string) self::esc_sql_ident( $host );
$user_identifier = $username_escaped . '@' . $host_escaped;
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esc_sql_ident() backticks identifiers (e.g., user), but MySQL account names in CREATE USER / GRANT ... TO syntax need to be string-literal quoted (e.g., 'user'@'host'). Using backticks here will fail for common hosts like % and may produce invalid SQL. Consider escaping username/host as SQL string literals (and building 'user'@'host') rather than using identifier escaping.

Suggested change
// Escape identifiers for SQL
// @phpstan-ignore cast.string (PHPStan doesn't infer conditional return type from parent method)
$username_escaped = (string) self::esc_sql_ident( $username );
// @phpstan-ignore cast.string (PHPStan doesn't infer conditional return type from parent method)
$host_escaped = (string) self::esc_sql_ident( $host );
$user_identifier = $username_escaped . '@' . $host_escaped;
// MySQL account names in CREATE USER / GRANT ... TO use string literals, not identifiers.
$username_escaped = $this->esc_sql_string( $username );
$host_escaped = $this->esc_sql_string( $host );
$user_identifier = $username_escaped . '@' . $host_escaped;

Copilot uses AI. Check for mistakes.
Comment thread src/DB_Users_Command.php
Comment on lines +106 to +119
* Follows MySQL's documented string literal escaping rules.
* See https://dev.mysql.com/doc/refman/en/string-literals.html
*
* @param string $value String to escape.
* @return string Escaped string, wrapped in single quotes.
*/
private function esc_sql_string( $value ) {
// Escape special characters according to MySQL string literal rules.
$value = str_replace(
[ '\\', "\x00", "\n", "\r", "'", '"', "\x1a" ],
[ '\\\\', "\\0", "\\n", "\\r", "\\'", '\\"', '\\Z' ],
$value
);
return "'" . $value . "'";
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esc_sql_string() relies on backslash escapes for quotes (e.g., \'). This will break (and can become unsafe) when the server/session has NO_BACKSLASH_ESCAPES enabled, because backslashes no longer escape quotes. Since run_query() doesn't remove that SQL mode, consider escaping single quotes by doubling them (''') or explicitly handling NO_BACKSLASH_ESCAPES when building the IDENTIFIED BY literal.

Suggested change
* Follows MySQL's documented string literal escaping rules.
* See https://dev.mysql.com/doc/refman/en/string-literals.html
*
* @param string $value String to escape.
* @return string Escaped string, wrapped in single quotes.
*/
private function esc_sql_string( $value ) {
// Escape special characters according to MySQL string literal rules.
$value = str_replace(
[ '\\', "\x00", "\n", "\r", "'", '"', "\x1a" ],
[ '\\\\', "\\0", "\\n", "\\r", "\\'", '\\"', '\\Z' ],
$value
);
return "'" . $value . "'";
* Uses SQL-standard single-quote escaping (`'` => `''`) so the generated
* literal remains valid even when MySQL is running with
* `NO_BACKSLASH_ESCAPES`.
*
* @param string $value String to escape.
* @return string Escaped string, wrapped in single quotes.
*/
private function esc_sql_string( $value ) {
return "'" . str_replace( "'", "''", $value ) . "'";

Copilot uses AI. Check for mistakes.
Comment thread src/DB_Users_Command.php
*
* # Create a new database user with privileges.
* $ wp db users create myuser myhost --password=mypass --grant-privileges
* Success: Database user 'myuser'@'myhost' created with privileges.
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class-level example output says the user is "created with privileges", but the implementation prints "created with privileges on database '...'." Updating the example output will keep docs consistent with the actual command behavior.

Suggested change
* Success: Database user 'myuser'@'myhost' created with privileges.
* Success: Database user 'myuser'@'myhost' created with privileges on database 'wp_database'.

Copilot uses AI. Check for mistakes.
Comment thread features/db-users.feature
Comment on lines +9 to +10
When I try `wp db create`
And I run `wp db users create testuser localhost --password=testpass123`
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scenarios use When I try wp db create but never assert the return code or output. If `wp db create` fails, the rest of the scenario can still pass because creating a MySQL user (and querying `mysql.user`) doesn’t require the WordPress DB to exist. Use `When I run `wp db create (or assert a 0 return code) to make the tests actually validate database creation.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce wp db users

4 participants